﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace SceneLib
{
    public class SceneBackground
    {
        public Vector Color {get; set;}
        public Vector AmbientLight { get; set; }

    }

    public class SceneLight
    {
        public float AtenuationConstant { get; set; }
        public float AtenuationLinear { get; set; }
        public float AtenuationQuadratic { get; set; }
        public Vector Color { get; set; }
        public Vector Position { get; set; }
        public Vector A { get; set; }
        public Vector B { get; set; }

    }

    public class SceneCamera
    {
        public Vector Position { get; set; }
        public Vector Target { get; set; }
        public Vector Up { get; set; }
        public Vector U { get; set; }
        public Vector V { get; set; }
        public Vector W { get; set; }
        public float FieldOfView { get; set; }
        public float NearClip { get; set; }
        public float FarClip { get; set; }        
    }

    public class SceneMaterial
    {
        public Bitmap TextureImage;
        private IntPtr ptrBitmap;

        public Bitmap BumpImage;
        private IntPtr ptrBumpBitmap;

        public Bitmap NormalImage;
        private IntPtr ptrNormalBitmap;

        public string Name { get; set; }
        public string TextureFile { get; set; }
        public string BumpFile { get; set; }
        public string NormalFile { get; set; }
        public Vector Diffuse { get; set; }
        public Vector Specular { get; set; }
        public Vector Transparent { get; set; }
        public Vector Reflective { get; set; }
        public Vector RefractionIndex { get; set; }
        public float Shininess { get { return Specular.w; } set { Specular.w = value; } }
        public IntPtr PtrBitmap {get { return ptrBitmap; } }
        public IntPtr PtrBumpBitmap { get { return ptrBumpBitmap; } }
        public IntPtr PtrNormalBitmap { get { return ptrNormalBitmap; } }

        public SceneMaterial()
        {
            Specular = new Vector(0, 0, 0);
            Diffuse = new Vector(0, 0, 0);
            Reflective = new Vector(0, 0, 0);
        }

        public Vector GetTexturePixelColor(int x, int y)
        {
            if (TextureImage == null)
                return null;
            //y = TextureImage.Height - 1 - y;    // cambio de coordenadas para que el origen 
            //                                    // quede en esquina inferior izquierda

            Color c = TextureImage.GetPixel(x, y);
            Vector color = new Vector(c.R/255.0f, c.G/255.0f, c.B/255.0f, c.A/255.0f);
            return color;
        }        

        public void CreatePointer() 
        {
            BitmapData data = this.TextureImage.LockBits(new Rectangle(0, 0, TextureImage.Height, TextureImage.Width),
            ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            
            ptrBitmap = data.Scan0;

            this.TextureImage.UnlockBits(data);

        }
               
        
    }

    public abstract class SceneObject
    {
        public string Name { get; set; }
        public Vector Scale { get; set; }
        public Vector Position { get; set; }
        public Vector Rotation { get; set; }
        
        public SceneObject()
        {
            Scale = new Vector(1, 1, 1);
            Position = new Vector(0, 0, 0);
            Rotation = new Vector(0, 0, 0);
        }
    }

    public class SceneSphere : SceneObject
    {
        public Vector Center { get; set; }
        public float Radius { get; set; }
        public SceneMaterial Material { get; set; }        
    }

    public class SceneTriangle : SceneObject
    {
        public List<Vector> Vertex { get; set; }
        public List<Vector> VertexClip { get; set; }
        public List<Vector> Normal { get; set; }
        public List<Vector> Colors { get; set; }
        public List<SceneMaterial> Materials { get; set; }
        public List<float> U { get; set; }
        public List<float> V { get; set; }

        public bool InClipCoords = false;

        public SceneTriangle()
        {
            Vertex = new List<Vector>();
            VertexClip = new List<Vector>();
            Normal = new List<Vector>();
            Materials = new List<SceneMaterial>();
            Colors = new List<Vector>();
            U = new List<float>();
            V = new List<float>();
        }       
    }

    public class SceneModel : SceneObject
    {
        public string FileName { get; set; }
        public List<SceneTriangle> Triangles { get; set; }
        public int NumTriangles { get { return Triangles == null ? 0 : Triangles.Count; } }

        public List<Vector> Vertices { get; set; }
        public List<Vector> Normals { get; set; }
        public List<Vector> TexCoords { get; set; }
        public List<Vector> Colors { get; set; }
        public List<int[]> Indexes { get; set; }

        public float[] VertexArray { get; set; }
        public float[] NormalsArray { get; set; }
        public float[] TexArray { get; set; }
        public short[] IndexArray { get; set; }
        public float[] ColorArray { get; set; }

        public SceneModel(string name, string filename)
        {
            Name = name;
            Triangles = new List<SceneTriangle>();
            FileName = filename;
            Vertices = new List<Vector>();
            Normals = new List<Vector>();
            TexCoords = new List<Vector>();
            Colors = new List<Vector>();
            Indexes = new List<int[]>();
        }

        public SceneTriangle GetTriangle(int index)
        {
            return Triangles == null || index < 0 || index > Triangles.Count ? null : Triangles[index];
        }

        public void CreateArrays()
        {
            VertexArray = GetVertexArray();
            NormalsArray = GetNormalArray();
            TexArray = GetTextureArray();
            IndexArray = GetFaceIndexes();
            ColorArray = GetColorArray();
        }

        public float[] GetVertexArray()
        {
            float[] array = new float[Vertices.Count * 3];

            int i = 0;
            foreach (Vector v in Vertices)
            {
                if (v != null)
                {
                    array[i++] = (float)v.x;
                    array[i++] = (float)v.y;
                    array[i++] = (float)v.z;
                }
                else
                {
                    array[i++] = 0.0f;
                    array[i++] = 0.0f;
                    array[i++] = 0.0f;
                }
                
            }
            return array;
        }

        public float[] GetNormalArray()
        {
            float[] array = new float[Normals.Count * 3];

            int i = 0;
            foreach (Vector v in Normals)
            {
                if (v != null)
                {
                    array[i++] = (float)v.x;
                    array[i++] = (float)v.y;
                    array[i++] = (float)v.z;
                }
                else
                {
                    array[i++] = 0.0f;
                    array[i++] = 0.0f;
                    array[i++] = 0.0f;
                }
            }
            return array;
        }

        public float[] GetColorArray()
        {
            float[] array = new float[Colors.Count * 3];

            int i = 0;
            foreach (Vector v in Colors)
            {
                if (v != null)
                {
                    array[i++] = (float)v.x;
                    array[i++] = (float)v.y;
                    array[i++] = (float)v.z;
                }
                else
                {
                    array[i++] = 0.0f;
                    array[i++] = 0.0f;
                    array[i++] = 0.0f;
                }
            }
            return array;
        }

        public float[] GetTextureArray()
        {
            float[] array = new float[TexCoords.Count * 2];

            int i = 0;
            foreach (Vector v in TexCoords)
            {
                if (v != null)
                {
                    array[i++] = (float)v.x;
                    array[i++] = (float)v.y;
                }
                else
                {
                    array[i++] = 0.0f;
                    array[i++] = 0.0f;
                }

            }
            return array;
        }

        public short[] GetFaceIndexes()
        {
            short[] array = new short[Indexes.Count * 3];

            int i = 0;
            foreach (int[] indexList in Indexes)
            {
                foreach (int idx in indexList)
                {
                    array[i++] = (short)idx;
                }
            }
            return array;
        }
    }


}
